package com.hh.mybatis.core.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.hh.common.core.domain.BaseEntity;
import com.hh.common.utils.spring.SpringUtils;
import com.hh.mybatis.core.service.IBaseService;
import com.hh.mybatis.core.mapper.BaseMapper;
import com.hh.mybatis.handler.DataFillHandler;
import com.hh.mybatis.utils.SqlHelper;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.aop.framework.AopProxyUtils;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;

/**
 * BaseService层处理
 *
 * @author hh
 * @date 2023-03-17
 */
public abstract class BaseServiceImpl<T extends BaseEntity> implements IBaseService<T> {
    @Resource
    private SqlSessionFactory sqlSessionFactory;

    public static <T extends BaseEntity, M extends BaseMapper<T>> Class<M> getMapperTarget(M mapper) {
        Class<M> mapperClass = null;
        Class<?>[] classes = AopProxyUtils.proxiedUserInterfaces(mapper);
        if (classes.length > 0) {
            mapperClass = (Class<M>) classes[0];
        }
        return mapperClass;
    }

    protected abstract BaseMapper<T> getBaseMapper();

    private Class<BaseMapper<T>> currentMapperClass() {
        return getMapperTarget(getBaseMapper());
    }

    /**
     * 根据id查询
     *
     * @param id 主键
     * @return 实体
     */
    @Override
    public T selectById(Serializable id) {
        return getBaseMapper().selectById(id);
    }

    /**
     * 根据ids查询
     *
     * @param ids 主键
     * @return 实体
     */
    @Override
    public List<T> selectByIds(Collection<? extends Serializable> ids) {
        return getBaseMapper().selectByIds(ids);
    }

    /**
     * 查询列表
     *
     * @param entity 实体列表
     * @return 集合
     */
    @Override
    public List<T> selectList(T entity) {
        return getBaseMapper().selectList(entity);
    }

    /**
     * 查询一条记录
     *
     * @param entity 实体列表
     * @return 结果
     */
    @Override
    public T selectOne(T entity) {
        List<T> list = getBaseMapper().selectList(entity);
        return CollUtil.isEmpty(list) ? null: list.get(0);
    }

    /**
     * 新增
     *
     * @param entity 实体
     * @return 结果
     */
    @Override
    public boolean insert(T entity) {

        DataFillHandler dataFillHandler = SpringUtils.getBeanNoException(DataFillHandler.class);
        if (ObjectUtil.isNotNull(dataFillHandler)) {
            dataFillHandler.insertFill(entity);
        }
        return SqlHelper.retBool(getBaseMapper().insert(entity));
    }

    /**
     * 先校验后修改
     *
     * @param entity 实体
     * @return 结果
     */
    @Override
    public boolean save(T entity) {

        checkSave(entity);
        return insert(entity);
    }

    /**
     * 新增前校验
     * @param entity
     */
    protected void checkSave(T entity)
    {

    }

    /**
     * 根据id修改
     *
     * @param entity 实体
     * @return 结果
     */
    @Override
    public boolean updateById(T entity) {
        DataFillHandler dataFillHandler = SpringUtils.getBeanNoException(DataFillHandler.class);
        if (ObjectUtil.isNotNull(dataFillHandler)) {
            dataFillHandler.updateFill(entity);
        }
        return SqlHelper.retBool(getBaseMapper().updateById(entity));
    }

    /**
     * 修改
     *
     * @param entity 实体
     * @return 结果
     */
    @Override
    public boolean update(T entity) {
        DataFillHandler dataFillHandler = SpringUtils.getBeanNoException(DataFillHandler.class);
        if (ObjectUtil.isNotNull(dataFillHandler)) {
            dataFillHandler.updateFill(entity);
        }
        return SqlHelper.retBool(getBaseMapper().update(entity));
    }

    /**
     * 先校验后修改
     *
     * @param entity 实体
     * @return 结果
     */
    @Override
    public boolean edit(T entity)
    {
        checkEdit(entity);
        return updateById(entity);
    }

    public void checkEdit(T entity)
    {

    }

    /**
     * 根据id删除
     *
     * @param id 主键
     * @return 结果
     */
    @Override
    public boolean deleteById(Serializable id) {
        return SqlHelper.retBool(getBaseMapper().deleteById(id));
    }

    /**
     * 根据ids批量删除
     *
     * @param ids 需要删除的数据主键集合
     * @return 结果
     */
    @Override
    public boolean deleteByIds(Collection<? extends Serializable> ids) {
        return SqlHelper.retBool(getBaseMapper().deleteByIds(ids));
    }

    /**
     * 批量新增
     *
     * @param list
     */
    @Override
    public void batchInsert(final List<T> list) {
        if (CollUtil.isEmpty(list)) {
            return;
        }
        DataFillHandler dataFillHandler = SpringUtils.getBeanNoException(DataFillHandler.class);
        for (T record : list) {
            if (ObjectUtil.isNotNull(dataFillHandler)) {
                dataFillHandler.insertFill(record);
            }
            getBaseMapper().insert(record);
        }
    }

    /**
     * TODO min 批量更新性能提升不大，待跟进处理
     * 批量更新
     *
     * @param list
     */
    @Override
    public void batchUpdate(final List<T> list) {
        if (CollUtil.isEmpty(list)) {
            return;
        }
        DataFillHandler dataFillHandler = SpringUtils.getBeanNoException(DataFillHandler.class);
        for (T record : list) {
            if (ObjectUtil.isNotNull(dataFillHandler)) {
                dataFillHandler.updateFill(record);
            }
            getBaseMapper().updateById(record);
        }
    }

    /**
     * 批量更新删除 此方法防止用deleteByIds时候，in中id集合超长
     *
     * @param ids
     */
    @Override
    public void batchDelete(final Collection<? extends Serializable> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) {
            BaseMapper mapper = session.getMapper(currentMapperClass());
            int batch = 0;
            for (Serializable record : ids) {
                mapper.deleteById(record);
                batch++;
                if (batch == 800) {
                    session.commit();
                    session.clearCache();
                    batch = 0;
                }
            }
            session.commit();
        }
    }
}
